﻿using JGSY.SerialCommunication.UpperComputer.Core;
using JGSY.SerialCommunication.UpperComputer.IComponent;
using RJCP.IO.Ports;
using System;
using System.Collections.Generic;
using System.Diagnostics; 
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JGSY.SerialCommunication.UpperComputer.Component
{
    /// <summary>
    /// 串口通讯类
    /// </summary>
    public class Serial : ICommunicationUnit, IDisposable
    {
        #region  属性  

        /// <summary>
        /// Modbus rtu 3.5 1.5
        /// 在 Modbus RTU 协议中，3.5 个字符时间（3.5T） 和 1.5 个字符时间（1.5T） 
        /// 是关键的 帧间隔（Inter-Frame Space） 和 字符间隔（Inter-Character Space） 时序要求，用于确保通信的可靠性。
        /// </summary>
        public int ReadTimeOut { get; set; } = 500;

        /// <summary>
        /// 连接超时
        /// </summary>
        public int ConnectTimeOut { get; set; } = 1000;

        /// <summary>
        /// 实例化操作对象（C# 串行端口类）
        /// </summary>
        private SerialPortStream _serialPort;

        /// <summary>
        /// 同步锁
        /// </summary>
        private readonly object _syncLock = new object();



        #endregion



        #region MyRegion
       
        private Serial() { }

        /// <summary>
        /// 构造函数初始化串行端口类
        /// </summary>
        /// <param name="portName">端口名称</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="dataBit">数据位</param>
        /// <param name="parity">校验位</param>
        /// <param name="stopBits">停止位</param>
        /// <param name="readTimeout">读取超时时间</param>
        public Serial(string portName, int baudRate, int dataBit, Parity parity, StopBits stopBits, int readTimeout)
        {
            _serialPort = new SerialPortStream
            {
                PortName = portName,
                BaudRate = baudRate,
                DataBits = dataBit,
                Parity = parity,
                StopBits = stopBits,
                ReadTimeout = readTimeout
            };

            ReadTimeOut = readTimeout;
        }
        #endregion


        #region 接收 发送【请求、响应】
        public Result<byte> SendAndRecevice1(List<byte> request, int receiveLen, int errorLen = 0)
        {
            var result = new Result<byte> { Datas = new List<byte>() };

            if (disposed)
            {
                result.Status = false;
                result.Message = "对象已被释放，无法进行通信";
                return result;
            }

            lock (_syncLock)
            {
                try
                {
                    if (_serialPort == null || !_serialPort.IsOpen)
                    {
                        throw new InvalidOperationException("串口未打开");
                    }

                    // 清空缓冲区
                    _serialPort.DiscardInBuffer();
                    _serialPort.DiscardOutBuffer();

                    // 发送数据
                    _serialPort.Write(request.ToArray(), 0, request.Count);

                    // 添加 Modbus RTU 3.5 个字符时间的静默期
                    Thread.Sleep(CalculateSilentTime(_serialPort.BaudRate));
                     
                    byte[] data = new byte[receiveLen * 2 + 5];// 正常    异常
                    _serialPort.Read(data, 0, data.Length);// 串口Read不卡线程    网口Scoket卡线程  事件
                    //for (int i = 3; i < data.Length - 2; i += 2)
                    //{ 
                    //    byte[] vb = new byte[2] { data[i + 1], data[i] };
                    //    ushort v = BitConverter.ToUInt16(vb);// 解析出无符号短整型数据
                    //    Console.WriteLine(v);
                    //}
                    // 检查是否接收到足够的数据
                    if (data.Length < receiveLen)
                    {
                        if (errorLen > 0 && data.Length >= errorLen)
                        {
                            // 处理错误响应
                            result.Status = false;
                            result.Message = "接收到错误响应";
                            result.Datas.AddRange(data);
                        }
                        else
                        {
                            throw new TimeoutException("接收数据超时");
                        }
                    }
                    else
                    {
                        result.Status = true;
                        result.Datas.AddRange(data);
                    }


                }
                catch (Exception ex)
                {
                    result.Status = false;
                    result.Message = $"通信过程中发生异常: {ex.Message}";
                }
            }

            return result;
        }
         

        public Result<byte> SendAndRecevice(List<byte> request, int receiveLen, int errorLen = 0)
        {
            var result = new Result<byte> { Datas = new List<byte>() };

            if (disposed)
            {
                result.Status = false;
                result.Message = "对象已被释放，无法进行通信";
                return result;
            }

            lock (_syncLock)
            {
                try
                {
                    if (_serialPort == null || !_serialPort.IsOpen)
                    {
                        throw new InvalidOperationException("串口未打开");
                    }

                    // 清空缓冲区
                    _serialPort.DiscardInBuffer();
                    _serialPort.DiscardOutBuffer();

                    // 发送数据
                    _serialPort.Write(request.ToArray(), 0, request.Count);

                    // 添加 Modbus RTU 3.5 个字符时间的静默期
                    Thread.Sleep(CalculateSilentTime(_serialPort.BaudRate));

                    // 定义常量
                    const int ASCII_FRAME_HEADER_LENGTH = 1; // ':'字符
                    const int ASCII_FRAME_TRAILER_LENGTH = 2; // CR/LF
                    const int RTU_MIN_FRAME_LENGTH = 4; // 最小RTU帧长度(地址+功能码+数据+CRC)

                    // 根据协议类型选择接收方式
                    bool isAsciiProtocol = request.Count > 0 && request[0] == ':';

                    List<byte> receivedData = new List<byte>();
                    DateTime startTime = DateTime.Now;
                    int timeoutMs = 1000; // 1秒超时

                    try
                    {
                        if (isAsciiProtocol)
                        {
                            // Modbus ASCII 协议接收逻辑
                            // 接收直到遇到CR/LF结束符或超时 
                            while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs)
                            {
                                if (_serialPort.BytesToRead > 0)
                                {
                                    byte data = (byte)_serialPort.ReadByte();
                                    receivedData.Add(data);

                                    // 检查是否接收到完整的 ASCII 帧（CR+LF 结尾）
                                    if (receivedData.Count >= 2 &&
                                        receivedData[receivedData.Count - 2] == 0x0D && // CR（ASCII 13）
                                        receivedData[receivedData.Count - 1] == 0x0A)   // LF（ASCII 10）
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    Thread.Sleep(1);
                                }
                            }

                            // 验证帧完整性（至少包含：起始符1字节 + 数据部分（至少2字节） + LRC 2字节 + 结束符2字节）
                            if (receivedData.Count < 1 + 2 + 2 + 2) // 最小帧长度校验
                            {
                                throw new InvalidDataException("接收到的 ASCII 帧不完整（长度不足）");
                            }

                            // 验证起始符（必须是 ':'，ASCII 58）
                            if (receivedData[0] != 0x3A) // 0x3A 对应 ':'
                            {
                                throw new InvalidDataException($"帧缺少起始符 ':'，实际起始字节为：{receivedData[0]}");
                            }

                            // 验证结束符（必须是 CR+LF，即 0x0D+0x0A）
                            if (receivedData[receivedData.Count - 2] != 0x0D || receivedData[receivedData.Count - 1] != 0x0A)
                            {
                                throw new InvalidDataException("帧缺少有效的结束符 CR+LF");
                            }

                            // 提取数据部分（不含起始符、LRC、结束符）
                            // 帧结构：[:][数据部分][LRC的2个ASCII字符][CR][LF]
                            int totalLength = receivedData.Count;
                            int dataAndLrcLength = totalLength - 3; // 减去起始符（1字节）和结束符（2字节）
                            if (dataAndLrcLength < 2) // 至少需要 2 字节（LRC的1个字符对）
                            {
                                throw new InvalidDataException("帧数据部分长度不足");
                            }

                            // 数据部分 = 所有数据（不含LRC和结束符）
                            byte[] dataPartAscii = receivedData.Skip(1).Take(dataAndLrcLength - 2).ToArray(); // 减去LRC的2个字符
                                                                                                              // LRC的ASCII字符对（2字节）
                            byte[] lrcAsciiPair = receivedData.Skip(1 + dataPartAscii.Length).Take(2).ToArray();

                            // 校验 LRC 的 ASCII 字符对是否有效（避免混入结束符）
                            if (lrcAsciiPair.Length != 2)
                            {
                                throw new InvalidDataException("LRC 字符对不完整");
                            }
                            if (!IsValidHexChar(lrcAsciiPair[0]) || !IsValidHexChar(lrcAsciiPair[1]))
                            {
                                throw new InvalidDataException(
                                    $"LRC 包含无效字符：高字节 '{(char)lrcAsciiPair[0]}'（ASCII {lrcAsciiPair[0]}），" +
                                    $"低字节 '{(char)lrcAsciiPair[1]}'（ASCII {lrcAsciiPair[1]}）");
                            }

                            // 将数据部分的 ASCII 转换为二进制
                            List<byte> dataPartBinary = new List<byte>();
                            for (int i = 0; i < dataPartAscii.Length; i += 2)
                            {
                                if (i + 1 >= dataPartAscii.Length)
                                {
                                    throw new InvalidDataException("数据部分长度不是偶数，无法转换为二进制");
                                }
                                byte high = ConvertHexChar(dataPartAscii[i]);
                                byte low = ConvertHexChar(dataPartAscii[i + 1]);
                                dataPartBinary.Add((byte)((high << 4) | low));
                            }

                            // 计算数据部分的 LRC
                            byte calculatedLrc = CalculateLrc(dataPartBinary.ToArray());

                            // 转换接收到的 LRC（ASCII 字符对 -> 二进制）
                            byte receivedLrc = ConvertAsciiBytePair(lrcAsciiPair[0], lrcAsciiPair[1]);

                            // 校验 LRC
                            if (calculatedLrc != receivedLrc)
                            {
                                throw new InvalidDataException(
                                    $"LRC 校验失败：计算值 0x{calculatedLrc:X2}，接收值 0x{receivedLrc:X2}");
                            }
                             
                        }
                        else
                        {
                            // Modbus RTU 协议接收逻辑
                            // 接收数据直到3.5个字符时间没有新数据
                            while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs)
                            {
                                if (_serialPort.BytesToRead > 0)
                                {
                                    // 有新数据，重置超时计时器
                                    startTime = DateTime.Now;

                                    // 读取所有可用字节
                                    int bytesToRead = _serialPort.BytesToRead;
                                    byte[] buffer = new byte[bytesToRead];
                                    _serialPort.Read(buffer, 0, bytesToRead);
                                    receivedData.AddRange(buffer);

                                    // 检查是否可能是完整帧
                                    if (receivedData.Count >= RTU_MIN_FRAME_LENGTH)
                                    {
                                        // 对于功能码03/04，数据长度在第3字节
                                        if (receivedData[1] == 0x03 || receivedData[1] == 0x04)
                                        {
                                            int expectedLength = 3 + receivedData[2] + 2; // 地址+功能码+长度+数据+CRC
                                            if (receivedData.Count >= expectedLength)
                                            {
                                                // 等待3.5个字符时间确认没有更多数据
                                                Thread.Sleep(CalculateSilentTime(_serialPort.BaudRate));
                                                if (_serialPort.BytesToRead == 0)
                                                {
                                                    break;
                                                }
                                            }
                                        }
                                        // 其他功能码可以添加类似的处理逻辑
                                    }
                                }
                                else
                                {
                                    Thread.Sleep(1); // 避免CPU占用过高
                                }
                            }

                            // 验证RTU帧
                            if (receivedData.Count < RTU_MIN_FRAME_LENGTH)
                            {
                                throw new InvalidDataException("接收到的RTU帧长度不足");
                            }

                            // 计算CRC校验
                            byte[] frameData = receivedData.Take(receivedData.Count - 2).ToArray();
                            ushort calculatedCrc = CalculateCrc(frameData);
                            ushort receivedCrc = (ushort)(receivedData[receivedData.Count - 2] | (receivedData[receivedData.Count - 1] << 8));

                            if (calculatedCrc != receivedCrc)
                            {
                                throw new InvalidDataException("RTU帧CRC校验失败");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("接收数据过程中发生错误", ex);
                    }

                    // 验证数据长度
                    if (receivedData.Count < receiveLen)
                    {
                        if (errorLen > 0 && receivedData.Count >= errorLen)
                        {
                            // 处理错误响应
                            result.Status = false;
                            result.Message = "接收到错误响应";
                            result.Datas.AddRange(receivedData);
                        }
                        else
                        {
                            throw new TimeoutException("接收数据超时");
                        }
                    }
                    else
                    {
                        result.Status = true;
                        result.Datas.AddRange(receivedData);
                    }
                }
                catch (Exception ex)
                {
                    result.Status = false;
                    result.Message = $"通信过程中发生异常: {ex.Message}";
                }
            }

            return result;
        }

        // 辅助方法
        private int CalculateSilentTime(int baudRate)
        {
            // 计算3.5个字符时间(毫秒)
            // 1个字符 = 11位(起始位+8数据位+校验位+停止位)
            double charTimeMs = (11.0 / baudRate) * 1000;
            return (int)Math.Ceiling(charTimeMs * 3.5);
        }

        private byte CalculateLrc(byte[] data)
        {
            byte lrc = 0;
            foreach (byte b in data)
            {
                lrc += b;
            }
            return (byte)(-(sbyte)lrc);
        }

     
        // 修复后的 ConvertAsciiBytePair 方法（调用 ConvertHexChar 前先校验）
        private byte ConvertAsciiBytePair(byte highNibble, byte lowNibble)
        {
            // 先检查高字节是否为有效十六进制字符
            if (!IsValidHexChar(highNibble))
            {
                throw new ArgumentException(
                    $"高字节为无效十六进制字符: (ASCII码: {highNibble})",
                    nameof(highNibble)
                );
            }
            // 再检查低字节是否为有效十六进制字符
            if (!IsValidHexChar(lowNibble))
            {
                throw new ArgumentException(
                    $"低字节为无效十六进制字符: (ASCII码: {lowNibble})",
                    nameof(lowNibble)
                );
            }

            // 转换为十六进制数值
            byte high = ConvertHexChar(highNibble);
            byte low = ConvertHexChar(lowNibble);
            return (byte)((high << 4) | low);
        }

        // 辅助方法：判断字符是否为有效的十六进制字符
        private bool IsValidHexChar(byte hexChar)
        {
            char c = (char)hexChar;
            return (c >= '0' && c <= '9') ||
                   (c >= 'A' && c <= 'F') ||
                   (c >= 'a' && c <= 'f');
        }
        private byte ConvertHexChar(byte hexChar)
        {
            // 将字节转换为字符（ASCII编码）
            char c = (char)hexChar;

            // 处理数字 0-9
            if (c >= '0' && c <= '9')
            {
                return (byte)(c - '0');
            }
            // 处理大写字母 A-F
            else if (c >= 'A' && c <= 'F')
            {
                return (byte)(c - 'A' + 10);
            }
            // 处理小写字母 a-f（之前可能缺少这部分）
            else if (c >= 'a' && c <= 'f')
            {
                return (byte)(c - 'a' + 10);
            }
            // 无效字符，抛出异常并说明具体字符（方便调试）
            else
            {
                throw new ArgumentException(
                    $"无效的十六进制字符: '{c}' (ASCII码: {hexChar})",
                    nameof(hexChar)
                );
            }
        }
         

        private ushort CalculateCrc(byte[] data)
        {
            ushort crc = 0xFFFF;

            foreach (byte b in data)
            {
                crc ^= (ushort)b;

                for (int i = 0; i < 8; i++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }

            return crc;
        }
        #endregion
 


        #region SerialPort 开启、关闭

        /// <summary>
        /// 关闭串行端口
        /// </summary>
        public void Close()
        {
            lock (_syncLock)
            {
                try
                {
                    if (_serialPort != null && _serialPort.IsOpen)
                    {
                        _serialPort.DiscardInBuffer();
                        _serialPort.DiscardOutBuffer();
                        _serialPort.Close();
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine($"关闭串口时发生异常: {ex.Message}");
                }
            }
        }

        public Result<bool> Open(int timeOut = -1)
        {
            var result = new Result<bool>();

            if (disposed)
            {
                result.Status = false;
                result.Message = "对象已被释放，无法打开串口";
                return result;
            }

            timeOut = timeOut > 0 ? timeOut : ConnectTimeOut;

            lock (_syncLock)
            {
                try
                {
                    if (_serialPort == null)
                    {
                        throw new InvalidOperationException("串口对象未初始化");
                    }

                    if (_serialPort.IsOpen)
                    {
                        result.Status = true;
                        return result;
                    }

                    var cancellationTokenSource = new CancellationTokenSource(timeOut);
                    var task = Task.Run(() =>
                    {
                        try
                        {
                            _serialPort.Open();
                            return true;
                        }
                        catch (Exception ex)
                        {
                            Trace.WriteLine($"打开串口时发生异常: {ex.Message}");
                            return false;
                        }
                    }, cancellationTokenSource.Token);

                    try
                    {
                        task.Wait(cancellationTokenSource.Token);
                        result.Status = task.Result;

                        if (!result.Status)
                        {
                            result.Message = "串口打开失败";
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        result.Status = false;
                        result.Message = "打开串口超时";
                    }
                    catch (AggregateException ex)
                    {
                        result.Status = false;
                        result.Message = $"打开串口时发生异常: {ex.InnerException?.Message ?? ex.Message}";
                    }
                }
                catch (Exception ex)
                {
                    result.Status = false;
                    result.Message = $"打开串口时发生异常: {ex.Message}";
                }
            }

            return result;
        }

        #endregion


        #region Dispose 资源释放
        //调用Dispose(false)：这是实现IDisposable模式的标准做法。Dispose(bool disposing)是一个受保护的虚方法，通常有两种调用场景：
        //Dispose(true)：由用户显式调用Dispose()时触发，同时释放托管资源和非托管资源。
        //Dispose(false)：由析构函数调用，仅释放非托管资源（因为此时托管资源可能已被垃圾回收）。

        /// <summary>
        /// 资源释放标识
        /// </summary>
        private bool disposed = false; 
        /// <summary>
        /// 实现IDisposable接口
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">是否释放托管资源</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // 释放托管资源
                    Close();
                    _serialPort?.Dispose();
                    _serialPort = null;
                }

                // 释放非托管资源

                disposed = true;
            }
        }
        /// <summary>
        /// 析构函数
        /// </summary>
        ~Serial()
        {
            Dispose(false);
        }
        #endregion
    }
}